﻿#define USE_ANIMATOR_OPTIMIZE
#define USE_SHADOW_OPTIMIZE

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UltimateGameTools;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using Yoozoo.Gameplay.RTS;
using Yoozoo.Mars.Got;
using Object = UnityEngine.Object;

namespace GameFramework.Battle.Tools
{
    public class BattleAnimationCompress
    {
        
        
        
        
        static void Tips(string tile, string strLog)
        {
            Debug.LogWarning(strLog);
        }

        static void Warning(string tile, string strLog)
        {
            Debug.LogError(strLog);

#if DISPLAY_DIALOG
            EditorUtility.DisplayDialog(tile, strLog , "OK");
#endif
        }

        static bool IsChina(string CString)
        {
            bool BoolValue = false;
            for (int i = 0; i < CString.Length; i++)
            {
                if (Convert.ToInt32(Convert.ToChar(CString.Substring(i, 1))) > Convert.ToInt32(Convert.ToChar(128)))
                {
                    BoolValue = true;
                }

            }
            return BoolValue;
        }

        //不能有空格，不能有中文字符
        public static bool IslegalString(string str)
        {
            if (str.IndexOf(" ") > -1)
                return false;

            if (IsChina(str))
                return false;

            return true;
        }

        static bool s_bGpuAnimation = true;
        static bool s_bMeshBake = false;

        private enum OptimizeType
        {
            None,
            Soldier,
            Commander,
            Moto,
            Wall,
            CityHero,
            CityNpc,
        }
 
        private static string m_fileAssetName;
        private static string m_assetName;
        private static string m_assetPath;
        private static string m_assetPrefabDirectory;
        private static string m_assetDirectory;
        private static string m_parentFolder = Application.dataPath.Replace("Assets", "");

        private static string m_prefabDirectory;


        private static ModelImporter m_importer;
        private static List<AnimationClip> m_clipList = new List<AnimationClip>();
        private static OptimizeType m_optimizeType;

        private static ExportInformation m_exportInformation;
        private static Avatar m_roleSourceAvatar;
        
        private static string SoldierShadowPrefabPath =
            "Assets/Arts/Character/Role/soldier/Soldier_shadow/role_shadow.prefab";
            
        private static string battle_normal_commander_controller  = "Assets/Arts/Character/Role/Common/controller/battle_normal_commander.controller";

        private static string battle_normal_wall_controller =
            "Assets/Arts/Character/Role/Common/controller/battle_normal_wall.controller";
        
        private static string gpuPrefabFolderPath = "Assets/ResourcesAssets/Prefabs/Character/Soldier/";
        private static string bakerPefabFolderPath = "Assets/ResourcesAssets/Prefabs/Character/Soldier/";

        [MenuItem("GTATools/Fbx/Export Model")]
        static void OptimizeAnimations()
        {
            //GetExportGameObject();
            Application.logMessageReceived += OnLogCallBack;
            s_bGpuAnimation = false;
            s_bMeshBake = false;

            GameObject[] objs = Selection.gameObjects;
            for (int i = 0; i < objs.Length; i++)
            {
                ExportFBXModel(objs[i]);
            }
            Application.logMessageReceived -= OnLogCallBack;
        }

        private static void OnLogCallBack(string condition, string stacktrace, LogType type)
        {
            
        }

        [MenuItem("GTATools/Fbx/Refresh Animation Hash")]
        static void RefreshAnimationHash()
        {

            string rootPath = System.Environment.CurrentDirectory;
           
            for (int i=0;i< Selection.assetGUIDs.Length;i++)
            {
                string AssetPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[i]);
                // Debug.Log(System.Environment.CurrentDirectory);
                string tempAssetPath = AssetPath.Replace("/", "\\");
                string fullPath = rootPath + "\\" + tempAssetPath;
                List<string> dirs = new List<string>();
                GetDirs(fullPath, ref dirs);
                for (int j = 0; j < dirs.Count; j++)
                {
                    RefreshAnimationHashMode(dirs[j]);
                   // GameObject obj;
                    //obj = AssetDatabase.LoadAssetAtPath(dirs[j], typeof(GameObject)) as GameObject;
                    //if (obj != null)
                    //{
                     
                    //    ExportFBXModel(obj);
                    //}
                    }

            }
                     
        }


     
        //参数1 为要查找的总路径， 参数2 保存路径
        private static void GetDirs(string dirPath, ref List<string> dirs)
        {
            foreach (string path in Directory.GetFiles(dirPath))
            {
                //获取所有文件夹中包含后缀为 .prefab 的路径
                //if (System.IO.Path.GetExtension(path) == ".FBX")
                if (System.IO.Path.GetExtension(path) == ".asset")
                {
                    dirs.Add(path.Substring(path.IndexOf("Assets")));                    
                }
            }

            if (Directory.GetDirectories(dirPath).Length > 0)  //遍历所有文件夹
            {
                foreach (string path in Directory.GetDirectories(dirPath))
                {
                    GetDirs(path, ref dirs);
                }
            }
        }

        [MenuItem("GTATools/GamePlay/Animation/GPU_instance_anim_only")]
        static void GPUAnimations()
        {
            s_bGpuAnimation = true;
            s_bMeshBake = false;

            GameObject[] objs = Selection.gameObjects;
            for (int i = 0; i < objs.Length; i++)
            {
                string targetPath = AssetDatabase.GetAssetPath(objs[i]);
                if (string.IsNullOrEmpty(targetPath))
                    continue;

                GameObject target = UnityEngine.Object.Instantiate<GameObject>(objs[i]);
                target.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);

                SkinnedMeshRenderer[] smr = target.GetComponentsInChildren<SkinnedMeshRenderer>();
                if (smr.Length == 0)
                {
                    Debug.LogError("Don't has SkinnedMeshRenderer component  " + target.name);
                    return;
                }

                Transform root = smr[0].rootBone;
                if (root == null)
                {
                    Debug.LogError("Don't has Root: " + target.name);
                    return;
                }

                List<KeyValuePair<Transform, int>> mappedIdx = ResortBone(target);

                foreach (var sm in smr)
                {
                    string meshPath = AssetDatabase.GetAssetPath(sm.sharedMesh);
                    if (File.Exists(m_parentFolder + meshPath.Replace("\\", "/")))
                    {
                        CheckOut(m_parentFolder + meshPath.Replace("\\", "/"));
                    }

                    RebulidMeshBindPose(target, sm, sm.sharedMesh, mappedIdx);

                    EditorUtility.SetDirty(sm.sharedMesh);
                }

                GPUInstancedAnimationGenerator gpuGenerator = new GPUInstancedAnimationGenerator(null);
                gpuGenerator.prefabFolderPath = gpuPrefabFolderPath;
                var validSkinnedMeshRenderers = new List<SkinnedMeshRenderer>(target.GetComponentsInChildren<SkinnedMeshRenderer>());
                //gpuGenerator.ToGenerate(gpuPrefabFolderPath, gpuPrefabFolderPath, string.Empty, target, validSkinnedMeshRenderers, objs[i].GetComponent<Animator>().runtimeAnimatorController, ref mappedIdx);
            }
        }

        [MenuItem("GTATools/GamePlay/Animation/修改动画Animator Culling Mode")]
        static void ChangeAnimatorCullingMode()
        {
            for (int i = 0; i < Selection.assetGUIDs.Length; i++)
            {
                string guid = Selection.assetGUIDs[i];
                string AssetPath = AssetDatabase.GUIDToAssetPath(guid);
                var asset = AssetDatabase.LoadAssetAtPath(AssetPath, typeof(GameObject));
                if (asset)
                {
                    var isPrefab = PrefabUtility.GetPrefabAssetType(asset) == PrefabAssetType.Regular;
                    if (isPrefab)
                    {
                        EditorUtility.DisplayProgressBar("正在修改Animator culling Mode:" + asset.name, asset.name, i / (float)Selection.assetGUIDs.Length);
                        var contentsRoot = PrefabUtility.LoadPrefabContents(AssetPath);
                        var obj = contentsRoot as GameObject;
                        var AnimatorArray = obj.transform.GetComponentsInChildren<Animator>();
                        for (int j = 0; j < AnimatorArray.Length; j++)
                        {
                            AnimatorArray[j].cullingMode = AnimatorCullingMode.CullCompletely;
                        }
                        PrefabUtility.SaveAsPrefabAsset(contentsRoot, AssetPath);
                        AssetDatabase.SaveAssets();
                        AssetDatabase.Refresh();
                        PrefabUtility.UnloadPrefabContents(contentsRoot);
                    }
                }
            }
            EditorUtility.ClearProgressBar();
        }

        static void ExportFBXModel(GameObject target)
        {
            m_assetPath = AssetDatabase.GetAssetPath(target);

            if (!m_assetPath.EndsWith(".fbx") && !m_assetPath.EndsWith(".FBX"))
            {
                Debug.LogError(m_assetPath + "---->please choose .FBX file");
                return;
            }

            m_fileAssetName = target.name;
            if (!m_fileAssetName.StartsWith("mesh_"))
            {
                Debug.LogError(m_fileAssetName + "---->please name start with mesh_");
                return;
            }

            m_assetName = m_fileAssetName.Replace("mesh_", "");
            //不能有中文、空格
            if (!IslegalString(m_assetName))
            {
                Warning("命名错误", string.Format("命名错误: {0}", m_assetName));
                return;
            }

            // 优化类型(命名按照使用场景来，具体看OptimizeType)
            m_optimizeType = GetOptimizeType(m_assetName);
            if (m_optimizeType == OptimizeType.None)
            {
                Debug.LogError(m_fileAssetName + "---->OptimizeType error");
                return;
            }
            Debug.LogWarning(m_fileAssetName + "---->OptimizeType:" + m_optimizeType.ToString());

            string toLowerName = m_assetName.ToLower();
            m_assetDirectory = Path.GetDirectoryName(m_assetPath);
            m_assetPrefabDirectory = Path.Combine(Path.GetDirectoryName(m_assetDirectory), "Prefabs");
            //创建资源 Prefabs的文件夹
            if (!Directory.Exists(m_assetPrefabDirectory))
            {
                Directory.CreateDirectory(m_assetPrefabDirectory);
            }
            //创建材质文件夹
            m_materialDirectory = Path.GetFullPath(Path.Combine(m_assetDirectory, "../Materials/")).Replace("\\", "/");
            m_materialDirectory = m_materialDirectory.Replace(System.Environment.CurrentDirectory.Replace("\\", "/") + "/", "");
            if (!Directory.Exists(m_materialDirectory))
            {
                Directory.CreateDirectory(m_materialDirectory);
            }
            //创建贴图文件夹
            m_textureDirectory = Path.Combine(Path.GetDirectoryName(m_assetDirectory), "Textures/").Replace("\\", "/");

            string sourceAnimatorControllerPath = string.Empty;
            //不同的类型，取不同的controller
            if (m_optimizeType == OptimizeType.Commander)
            {
                sourceAnimatorControllerPath = battle_normal_commander_controller;
                m_prefabDirectory = "Assets/ResourcesAssets/Prefabs/Character/Commander";// + m_assetName + ".prefab";
            }
            else if (m_optimizeType == OptimizeType.Wall)
            {
                sourceAnimatorControllerPath = battle_normal_wall_controller;
                m_prefabDirectory = "Assets/ResourcesAssets/Prefabs/Model/Battle";
            }
            else if (m_optimizeType == OptimizeType.Moto)
            {
                sourceAnimatorControllerPath = "Assets/Arts/Character/Role/soldier/Animator/RTS/rts_animator_moto.controller";
                m_prefabDirectory = "Assets/ResourcesAssets/Prefabs/Character/Soldier";
            }
            else if (m_optimizeType == OptimizeType.CityNpc)
            {
                sourceAnimatorControllerPath = "Assets/Arts/Character/Role/City/RTS300/Animators/con_HERO_InCity_male_02.controller";
                m_prefabDirectory = "Assets/ResourcesAssets/Prefabs/Incity_Ai/GpuSkinning";
            }
            else if (m_optimizeType == OptimizeType.CityHero)
            {
                sourceAnimatorControllerPath = "Assets/Arts/Character/Role/City/RTS300/Animators/con_HERO_InCity_male_01.controller";
                m_prefabDirectory = "Assets/ResourcesAssets/Prefabs/Incity_Ai/GpuSkinning";
            }
            else if (m_optimizeType == OptimizeType.Soldier)
            {
                sourceAnimatorControllerPath = "Assets/Arts/Character/Role/soldier/Animator/RTS/rts_animator_soldier.controller";
                m_prefabDirectory = "Assets/ResourcesAssets/Prefabs/Character/Soldier";// + m_assetNarts_me + ".prefab";
            }


            CheckOut(m_parentFolder + m_assetPath.Replace("\\", "/"));
             
            // 设置导入器
            m_importer = AssetImporter.GetAtPath(m_assetPath) as ModelImporter;
            m_importer.optimizeMesh = true;
            m_importer.meshCompression = ModelImporterMeshCompression.Medium;
            m_importer.weldVertices = true;
            m_importer.materialImportMode = ModelImporterMaterialImportMode.None;
            m_importer.optimizeGameObjects = false;
            m_importer.isReadable = false;

            m_importer.importNormals = ModelImporterNormals.Import;
            m_importer.importTangents = ModelImporterTangents.None;

            m_importer.SaveAndReimport();
            //获取导入信息
            m_exportInformation = GetExportInformation(m_assetName,m_optimizeType);

            GetFullPaths(target.transform, m_exportInformation.logicBones);

            InitalizeRigAndAnimationImporter(true, null);

            if (!GetAvatar(m_assetPath))
                return;

            GetAnimClips(m_assetPath);

            string targetAnimatorControllerPath = Path.Combine(m_assetDirectory, m_assetName) + ".controller";
            GetSourceAnimatorControllerTransitions(targetAnimatorControllerPath);
            RuntimeAnimatorController runtimeAnimator0 = CreateTargetAnimatorController(sourceAnimatorControllerPath, targetAnimatorControllerPath);

            if (m_optimizeType == OptimizeType.Commander 
                || m_optimizeType == OptimizeType.Soldier
                || m_optimizeType == OptimizeType.Moto
                || m_optimizeType == OptimizeType.CityNpc
                || m_optimizeType == OptimizeType.CityHero)
            {
                //只有小兵会生成GPUAnimation?
               // s_bGpuAnimation = m_optimizeType == OptimizeType.Soldier ? true : false;
               s_bGpuAnimation =  true;
                RuntimeAnimatorController runtimeAnimator1 = null;
                if (m_assetName.ToLower().StartsWith("world_monster"))
                {
                    sourceAnimatorControllerPath = "Assets/Arts/Character/Role/Common/controller/world_monster_commander.controller";
                    targetAnimatorControllerPath = Path.Combine(m_assetDirectory, m_assetName) + "_outcity.controller";
                    GetSourceAnimatorControllerTransitions(targetAnimatorControllerPath);
                    runtimeAnimator1 = CreateTargetAnimatorController(sourceAnimatorControllerPath, targetAnimatorControllerPath);
                }

                ExportCharacterPrefab(target, runtimeAnimator0, runtimeAnimator1);
            }
            else
                ExportPrefabByList(target, runtimeAnimator0, m_exportInformation.prefabs);


//            P4Utils.P4RevertUnchange();

            m_roleSourceAvatar = null;
            m_assetPath = null;
            m_assetDirectory = null;

            m_transitionConditions.Clear();

            m_clipList.Clear();
            Selection.activeObject = null;
            AssetDatabase.Refresh();
            m_importer = null;

            EditorUtility.DisplayDialog("通知", "导出成功", "OK");
        }


        static void RefreshAnimationHashMode(string target)
        {
            if (AssetDatabase.LoadAssetAtPath(target, typeof(ScriptableObject)) != null)
            {
                GPUSkinning_AllBoneAnimation m_sceneSettings_old = AssetDatabase.LoadAssetAtPath(target, typeof(ScriptableObject)) as GPUSkinning_AllBoneAnimation;
                GPUSkinning_AllBoneAnimation m_sceneSettings_new = UnityEngine.Object.Instantiate(m_sceneSettings_old);
//                P4Utils.P4CheckOut(target);
                //m_sceneSettings_new = m_sceneSettings_old;
                for (int i = 0; i < m_sceneSettings_new.parameters.Length; i++)
                {                 
                    AnimatorControllerParameter param = new AnimatorControllerParameter();
                    GPUSkinning_StateParameter gpuParam = m_sceneSettings_new.parameters[i];                   
                    gpuParam.hashCode = gpuParam.name.GetHashCode();                   
                    gpuParam.value = param.defaultFloat;
                    m_sceneSettings_new.parameters[i] = gpuParam;
                }
                //AssetDatabase.DeleteAsset(target);
                AssetDatabase.CreateAsset(m_sceneSettings_new, target);
                //AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }
           
        }

        private static string[] m_extraExposedTransformPaths;

        //获取所有配置骨骼的全路径
        private static void GetFullPaths(Transform target, List<string> paths)
        {
            List<string> fullPaths = new List<string>();
            for (int i = 0; i < paths.Count; i++)
            {
                string fullPath = GetFullPath(target, paths[i]);
                if (fullPath == null)
                {
                    Debug.LogError(string.Format("fullPath is error:{0} -> {1}", m_assetName, paths[i]));
                }
                else
                {
                    fullPaths.Add(fullPath);
                }
            }
            m_extraExposedTransformPaths = fullPaths.ToArray();
        }

        private static string GetFullPath(Transform target, string path)
        {
            Transform obj = Find(target, path);
            if (obj != null)
            {
                StringBuilder sb = new StringBuilder();
                sb.Insert(0, obj.name);
                RecursivePath(target, obj, ref sb);
                return sb.ToString();
            }
            return null;
        }

        private static void RecursivePath(Transform target, Transform root, ref StringBuilder sb)
        {
            Transform parent = root.parent;
            if (!parent.name.Equals(target.name))
            {
                sb.Insert(0, parent.name + "/");
                RecursivePath(target, parent, ref sb);
            }
        }

        private static Transform Find(Transform target, string name)
        {
            foreach (Transform child in target.GetComponentsInChildren<Transform>())
            {
                if (child.name == name)
                {
                    return child;
                }
            }
            return null;
        }

        private static Transform FindObj(GameObject target, string name)
        {
            foreach (Transform child in target.GetComponentsInChildren<Transform>())
            {
                if (child.name == name)
                {
                    return child;
                }
            }
            return null;
        }

     
        private static RuntimeAnimatorController CreateTargetAnimatorController(string sourceAnimatorControllerPath, string targetAnimatorControllerPath)
        {
            AssetDatabase.CopyAsset(sourceAnimatorControllerPath, targetAnimatorControllerPath);
            AnimatorController targetAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(targetAnimatorControllerPath);
            AnimatorControllerLayer animatorLayer = targetAnimatorController.layers[0];

            RecursiveStateMachine(animatorLayer.stateMachine);

            return targetAnimatorController;
        }

        //将新建的AnimatorController中的AnimatorState上的Transition赋值为之前存的值(会有不同么？)
        private static void RecursiveStateMachine(AnimatorStateMachine sm)
        {
            ChildAnimatorState[] childStates = sm.states;
            for (int i = 0; i < childStates.Length; i++)
            {
                AnimatorState state = childStates[i].state;
                string a = state.name;
                if (state.name.Contains("@"))
                {
                    int xI = state.name.LastIndexOf('@');
                    a = state.name.Substring(0, xI);
                }
                int j = 0;
                for (; j < m_clipList.Count; j++)
                {
                    AnimationClip clip = m_clipList[j];
                   
                    if (a == clip.name)
                    {
                        state.motion = clip;
                        if (m_existCondition)
                        {
                            AnimatorStateTransition[] transitions = state.transitions;
                            for (int k = 0; k < transitions.Length; k++)
                            {
                                //
                                AnimatorStateTransition transition = transitions[k];
                                TransitionCondition condition = GetTransitionCondition(state.name, transition.destinationState.name);
                                if (condition != null)
                                {
                                    transition.exitTime = condition.exitTime;
                                    transition.duration = condition.duration;
                                    transition.offset = condition.offset;
                                    transition.hasExitTime = condition.hasExitTime;
                                    transition.hasFixedDuration = condition.hasFixedDuration;
                                    transition.canTransitionToSelf = condition.canTransitionToSelf;
                                    transition.interruptionSource = (TransitionInterruptionSource)condition.interruptionSource;
                                    transition.orderedInterruption = condition.orderedInterruption;
                                }
                            }
                        }
                        break;
                    }
                }

                if (j == m_clipList.Count)
                {
                    Debug.LogErrorFormat("模型中缺少 animatoin clip：{0} ",state.name);
                }
            }
            ChildAnimatorStateMachine[] childSms = sm.stateMachines;
            for (int i = 0; i < childSms.Length; i++)
            {
                RecursiveStateMachine(childSms[i].stateMachine);
            }
        }

        private static TransitionCondition GetTransitionCondition(string source, string target)
        {
            for (int i = 0; i < m_transitionConditions.Count; i++)
            {
                TransitionCondition condition = m_transitionConditions[i];
                if (condition.source.Equals(source) && condition.target.Equals(target))
                {
                    return condition;
                }
            }
            return null;
        }

        //浮点数精度压缩到f3
        private static void OptimizeFloatingPoint(AnimationClip newClip)
        {
            Keyframe key;
            Keyframe[] keyFrames;
            AnimationClipCurveData[] curves = AnimationUtility.GetAllCurves(newClip);
            for (int i = 0; i < curves.Length; ++i)
            {
                AnimationClipCurveData curveData = curves[i];
                if (curveData.curve == null || curveData.curve.keys == null)
                {
                    continue;
                }
                keyFrames = curveData.curve.keys;
                for (int j = 0; j < keyFrames.Length; j++)
                {
                    key = keyFrames[j];
                    key.value = float.Parse(key.value.ToString("f3"));
                    key.inTangent = float.Parse(key.inTangent.ToString("f3"));
                    key.outTangent = float.Parse(key.outTangent.ToString("f3"));
                    keyFrames[j] = key;
                }
                curveData.curve.keys = keyFrames;
                newClip.SetCurve(curveData.path, curveData.type, curveData.propertyName, curveData.curve);
            }
        }

        private static List<TransitionCondition> m_transitionConditions = new List<TransitionCondition>();
        private static bool m_existCondition;

        private static void GetSourceAnimatorControllerTransitions(string targetAnimatorControllerPath)
        {
            m_transitionConditions.Clear();
            if (File.Exists(targetAnimatorControllerPath))
            {
                AnimatorController originalAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(targetAnimatorControllerPath);
                AnimatorControllerLayer originalControllerLayer = originalAnimatorController.layers[0];
                RecursiveTransitionCondition(originalControllerLayer.stateMachine);
                CheckOut(m_parentFolder + targetAnimatorControllerPath);
                //File.Delete(m_targetAnimatorControllerPath);
                originalControllerLayer = null;
                originalAnimatorController = null;
                m_existCondition = m_transitionConditions.Count > 0;
            }
            else
            {
                m_existCondition = false;
            }
        }

        //递归获取融合信息
        private static void RecursiveTransitionCondition(AnimatorStateMachine sm)
        {
            ChildAnimatorState[] childStates = sm.states;
            for (int i = 0; i < childStates.Length; i++)
            {
                AnimatorState state = childStates[i].state;
                AnimatorStateTransition[] transitions = state.transitions;
                for (int j = 0; j < transitions.Length; j++)
                {
                    AnimatorStateTransition transition = transitions[j];
                    TransitionCondition condition = new TransitionCondition();
                    condition.source = state.name;
                    condition.target = transition.destinationState.name;
                    condition.exitTime = transition.exitTime;
                    condition.hasExitTime = transition.hasExitTime;
                    condition.duration = transition.duration;
                    condition.offset = transition.offset;
                    condition.hasFixedDuration = transition.hasFixedDuration;
                    condition.canTransitionToSelf = transition.canTransitionToSelf;
                    condition.interruptionSource = (int)transition.interruptionSource;
                    condition.orderedInterruption = transition.orderedInterruption;
                    m_transitionConditions.Add(condition);
                }
            }
            ChildAnimatorStateMachine[] childSms = sm.stateMachines;
            for (int i = 0; i < childSms.Length; i++)
            {
                RecursiveTransitionCondition(childSms[i].stateMachine);
            }
        }

        private static int CompareTransform(Transform A, Transform B)
        {
            return A.name.CompareTo(B.name);
        }

        private static List<KeyValuePair<Transform, int>> ResortBone(GameObject target)
        {
            SkinnedMeshRenderer[] smr = target.GetComponentsInChildren<SkinnedMeshRenderer>();
            if (smr.Length == 0)
            {
                Debug.LogError("Don't has SkinnedMeshRenderer component  " + target.name);
                return null;
            }

            Transform root = smr[0].rootBone;
            if (root == null)
            {
                Debug.LogError("Don't has Root: " + target.name);
                return null;
            }

            List<KeyValuePair<Transform, int>> mappedIdx = new List<KeyValuePair<Transform, int>>();
            foreach (var sm in smr)
            {
                if (root != sm.rootBone)
                {
                    Debug.LogError(sm.name + ":Root bone error:" + sm.rootBone.name);
                    continue;
                }

                Transform[] smBones = sm.bones;
                foreach (var b in smBones)
                {
                    if (mappedIdx.FindIndex(x => x.Key == b) == -1)
                    {
                        mappedIdx.Add(new KeyValuePair<Transform, int>(b, mappedIdx.Count));
                    }
                }
            }

            return mappedIdx;
        }

        /// <summary>
        /// 主要作用： 将targetMesh的 顶点、法线根据骨骼影响转换，并存储；将骨骼、权重存到UV1上
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="sm"></param>
        /// <param name="targetMesh"></param>
        /// <param name="inRemapBones"></param>
        private static void RebulidMeshBindPose(GameObject obj, SkinnedMeshRenderer sm, Mesh targetMesh, List<KeyValuePair<Transform, int>> inRemapBones)
        {
            // Init Bones
            Transform[] aBones = sm.bones;
            int numBones = aBones.Length;

            int[] remapIdx = new int[numBones];
            for (int i = 0; i < numBones; ++i)
                remapIdx[i] = i;

            if (inRemapBones != null && inRemapBones.Count > 0)
            {
                for (int i = 0; i < numBones; ++i)
                {
                    if (inRemapBones.FindIndex(x => x.Key == sm.bones[i]) == -1)
                    {
                        Debug.LogError(targetMesh.name + ":在 mappedIdx 没有找到 Transform:" + sm.bones[i].name);
                        continue;
                    }
                    KeyValuePair<Transform, int> idx = inRemapBones.Find(x => x.Key == sm.bones[i]);
                    remapIdx[i] = idx.Value;
                }
            }

            
            Vector3[] aNormals = targetMesh.normals;
            Vector3[] aVertices = targetMesh.vertices;
            //切线存了顶点受到的骨骼权重
            List<Vector3> tangents = new List<Vector3>();
            
            Matrix4x4[] aBindPoses = targetMesh.bindposes;
            BoneWeight[] aBoneWeights = targetMesh.boneWeights;
            //将顶点、法线转到世界空间下；将切线存储骨骼、权重信息
            for (int i = 0; i < targetMesh.vertexCount; ++i)
            {
                Vector3 tangent = Vector3.zero;
                Vector3 v3Normal = Vector3.zero;
                Vector3 v3World = Vector3.zero;
                BoneWeight bw = aBoneWeights[i];
                if (Mathf.Abs(bw.weight0) > 0.00001f)
                {
                    Transform bone = (aBones == null || aBones.Length == 0) ? obj.transform : aBones[bw.boneIndex0].transform;
                    v3World = (bone.localToWorldMatrix * aBindPoses[bw.boneIndex0]).MultiplyPoint3x4(aVertices[i]) * bw.weight0;
                    v3Normal = (bone.localToWorldMatrix * aBindPoses[bw.boneIndex0]).MultiplyVector(aNormals[i]) * bw.weight0;
                    tangent.x = remapIdx[bw.boneIndex0]; //哪根骨骼
                    tangent.y = bw.weight0;//权重多少
                }
                else
                {
                    Debug.LogWarning(targetMesh + " Idx:" + i + ": Bone 0 weight == 0.0f.");
                }

                if (Mathf.Abs(bw.weight1) > 0.00001f)
                {
                    Transform bone = (aBones == null || aBones.Length == 0) ? obj.transform : aBones[bw.boneIndex1].transform;
                    v3World += (bone.localToWorldMatrix * aBindPoses[bw.boneIndex1]).MultiplyPoint3x4(aVertices[i]) * bw.weight1;
                    v3Normal += (bone.localToWorldMatrix * aBindPoses[bw.boneIndex1]).MultiplyVector(aNormals[i]) * bw.weight1;

                    tangent.z = remapIdx[bw.boneIndex1]; //第二根骨骼
                    //tangent.w = bw.weight1;   //这里为啥注释掉了？通过1-y算？
                }
                else
                {
                    tangent.y = 1.0f;
                    tangent.z = tangent.x;
                    //tangent.w = 0.0f;
                }

                if (Mathf.Abs(bw.weight2) > 0.00001f)
                {
                    Transform bone = (aBones == null || aBones.Length == 0) ? obj.transform : aBones[bw.boneIndex2].transform;
                    v3World += (bone.localToWorldMatrix * aBindPoses[bw.boneIndex2]).MultiplyPoint3x4(aVertices[i]) * bw.weight2;
                    v3Normal += (bone.localToWorldMatrix * aBindPoses[bw.boneIndex2]).MultiplyVector(aNormals[i]) * bw.weight2;

                    Debug.LogWarning(targetMesh + " Idx:" + i + ": Bone weight > 2.");
                }
                if (Mathf.Abs(bw.weight3) > 0.00001f)
                {
                    Transform bone = (aBones == null || aBones.Length == 0) ? obj.transform : aBones[bw.boneIndex3].transform;
                    v3World += (bone.localToWorldMatrix * aBindPoses[bw.boneIndex3]).MultiplyPoint3x4(aVertices[i]) * bw.weight3;
                    v3Normal += (bone.localToWorldMatrix * aBindPoses[bw.boneIndex3]).MultiplyVector(aNormals[i]) * bw.weight3;

                    Debug.LogWarning(targetMesh + " Idx:" + i + ": Bone weight > 3.");
                }
                aVertices[i] = v3World;
                aNormals[i] = v3Normal;
                tangents.Add(tangent);
            }

            for (int bpIdx = 0; bpIdx < aBindPoses.Length; bpIdx++)
            {
                aBindPoses[bpIdx] = aBones[bpIdx].worldToLocalMatrix * obj.transform.localToWorldMatrix;
            }

            targetMesh.vertices = aVertices;
            targetMesh.normals = aNormals;
            targetMesh.bindposes = aBindPoses;
            //将骨骼信息烘培到UV1上
            if (s_bGpuAnimation)
                targetMesh.SetUVs(1, tangents);
        }

        
        //导出角色的Prefab
        private static void ExportCharacterPrefab(GameObject obj, RuntimeAnimatorController modelAnimatorA,
            RuntimeAnimatorController modelAnimatorB)
        {
            //根节点要相同
            SkinnedMeshRenderer[] smr = obj.GetComponentsInChildren<SkinnedMeshRenderer>();
            string rootBoneName = smr[0].rootBone.name;
            for (int i = 0; smr != null && i < smr.Length; i++)
            {
                if (!rootBoneName.Equals(smr[i].rootBone.name))
                {
                    Warning("Root error", "Root不相同:" + smr[i].name);
                    return;
                }
            }
            //记录fbx的Mesh，与新生成的Mesh
            List<KeyValuePair<Mesh, Mesh>> rebindpose = new List<KeyValuePair<Mesh, Mesh>>();
            //获取所有的骨骼Transform
            List<KeyValuePair<Transform, int>> remapBones = ResortBone(obj);
            for (int s = 0; smr != null && s < smr.Length; s++)
            {
                if (!IslegalString(smr[s].name))
                {
                    string strLog = string.Format("Mesh  命名错误: {0} -> {1}", obj.name, smr[s].name);
                    Warning("命名错误", strLog);
                    continue;
                }

                SkinnedMeshRenderer sm = smr[s];
                string meshName = sm.sharedMesh.name;
                string levelName = meshName.Replace(m_assetName, string.Empty);
                //为啥_high就返回？
                if (levelName.Contains("_high")) continue;
                Mesh targetMesh = null;

                string meshPath = Path.Combine(Path.GetDirectoryName(m_assetPath), meshName) + "_mesh.asset";
                // 清理掉老的mesh.asset
                if (File.Exists(m_parentFolder + meshPath.Replace("\\", "/")))
                {
                    CheckOut(m_parentFolder + meshPath.Replace("\\", "/"));
                    AssetDatabase.DeleteAsset(meshPath);
                }
                //只允许有一个subMesh
                if (sm.sharedMesh.subMeshCount > 1)
                {
                    Debug.LogError("Not subMeshCount > 1:" + meshName);
                    continue;
                }

                targetMesh = UnityEngine.Object.Instantiate<Mesh>(sm.sharedMesh);
                targetMesh.uv2 = null;
                targetMesh.uv3 = null;
                AssetDatabase.CreateAsset(targetMesh, meshPath);

                if (s_bGpuAnimation)
                    RebulidMeshBindPose(obj, sm, targetMesh, remapBones);

                EditorUtility.SetDirty(targetMesh);

                rebindpose.Add(new KeyValuePair<Mesh, Mesh>(sm.sharedMesh, targetMesh));
            }
            // 生成GPUSkinning信息
            GPUSkinning_AllBoneAnimation gpuAnim = null;
            if (s_bGpuAnimation && remapBones != null)
            {
                GPUInstancedAnimationGenerator generator = new GPUInstancedAnimationGenerator(null);
                var validSkinnedMeshRenderers = new List<SkinnedMeshRenderer>(obj.GetComponentsInChildren<SkinnedMeshRenderer>());
                //generator.ToGenerate(gpuPrefabFolderPath, gpuPrefabFolderPath, m_assetName, obj, validSkinnedMeshRenderers, modelAnimatorA, ref remapBones);
                gpuAnim = generator.m_allBoneAnimation;
                if (gpuAnim == null)
                {
                    Debug.LogError("GPU Anim error:" + m_assetName);
                    return;
                }
            }

            float offset = 0.0f;
            for (int s = 0; smr != null && s < smr.Length; s++)
            {
                string assetName = smr[s].gameObject.name;
                string levelName = assetName.Replace(m_assetName, string.Empty);
                if (levelName.Contains("_high")) continue;

                SkinnedMeshRenderer sm = smr[s];
                string prefabName = sm.name;

                GameObject cloneTarget = UnityEngine.Object.Instantiate<GameObject>(obj);
                cloneTarget.name = assetName;

                Mesh targetMesh = null;

                SkinnedMeshRenderer[] targetSmr = cloneTarget.GetComponentsInChildren<SkinnedMeshRenderer>();
                for (int d = 0; targetSmr != null && d < targetSmr.Length; d++)
                {
                    if (!targetSmr[d].name.Equals(prefabName))
                    {
                        UnityEngine.Object.DestroyImmediate(targetSmr[d].gameObject);
                    }
                    else
                    {
                        targetMesh = rebindpose.Find(x => x.Key == targetSmr[d].sharedMesh).Value;

                        targetSmr[d].sharedMesh = targetMesh;
                        targetSmr[d].gameObject.layer = LayerMask.NameToLayer("Default");
                    }
                }

                string matName = assetName;
                matName = matName.Substring(0, matName.LastIndexOf("_"));

                Animator animator = cloneTarget.GetComponent<Animator>();
                if (animator != null)
                {
                    animator.avatar = m_roleSourceAvatar;
                    animator.runtimeAnimatorController = modelAnimatorA;
                }

                MatInformation matInformation = new MatInformation();
                matInformation.matName = "mat_"+matName;
                matInformation.shaderName = "Mobile/Model/TextureMask";
                Material shadowPlane_mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/Arts/Character/Role/soldier/slg/shadow_plane.mat");

                SkinnedMeshRenderer renderer = cloneTarget.GetComponentInChildren<SkinnedMeshRenderer>();
                renderer.sharedMaterials = new Material[] { AddMaterial(matInformation), shadowPlane_mat };

                if (!s_bGpuAnimation)
                {
                    GameObject logicTarget = UnityEngine.Object.Instantiate<GameObject>(cloneTarget);

                    Animator animatorOp = logicTarget.GetComponent<Animator>();
#if USE_ANIMATOR_OPTIMIZE
                    if (animatorOp.hasTransformHierarchy)
                    {
                        AnimatorUtility.OptimizeTransformHierarchy(logicTarget, m_extraExposedTransformPaths.ToArray());
                    }
#endif
                    SetHookPoint(logicTarget);
                    AddPrefabComponent(logicTarget);

                    string targetPath = Path.Combine(m_prefabDirectory, prefabName + ".prefab").Replace("\\", "/");
                    UnityEngine.Object tempPrefab = null;
                    if (File.Exists(targetPath))
                    {
//                        P4Utils.P4CheckOut(m_parentFolder + targetPath);
                        tempPrefab = AssetDatabase.LoadAssetAtPath(targetPath, typeof(GameObject));
                    }
                    else
                    {
                        tempPrefab = PrefabUtility.CreateEmptyPrefab(targetPath);
                    }

//                    AudioStudio.AnimationSound audio = !(tempPrefab is GameObject) ? null : (tempPrefab as GameObject).GetComponent<AudioStudio.AnimationSound>();
//                    if (audio == null)
//                    {
//                        audio = logicTarget.AddComponent<AudioStudio.AnimationSound>();
//                        audio.IsUpdatePosition = false;
//                        audio.IsEnvironmentAware = false;
//                    }
//                    else
//                    {
//                        AudioStudio.AnimationSound dest = logicTarget.AddComponent<AudioStudio.AnimationSound>();
//                        EditorUtility.CopySerialized(audio, dest);
//                    }

                    PrefabUtility.ReplacePrefab(logicTarget, tempPrefab, ReplacePrefabOptions.ConnectToPrefab);
                    UnityEngine.Object.DestroyImmediate(logicTarget);

                }

                if(modelAnimatorB != null)
                {
                    GameObject logicTarget = UnityEngine.Object.Instantiate<GameObject>(cloneTarget);

                    Animator animatorLogic = logicTarget.GetComponent<Animator>();
                    if (animatorLogic)
                    {
                        animatorLogic.avatar = m_roleSourceAvatar;
                        animatorLogic.runtimeAnimatorController = modelAnimatorB;
                    }

                    matInformation.matName = matName + "_outcity";
                    matInformation.shaderName = "Mobile/World/TextureMask";
                    Material shadowPlane_world_mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/Arts/Character/Role/soldier/slg/shadow_plane_world.mat");

                    SkinnedMeshRenderer rendererLogic = logicTarget.GetComponentInChildren<SkinnedMeshRenderer>();
                    rendererLogic.sharedMaterials = new Material[] { AddMaterial(matInformation), shadowPlane_world_mat };

#if USE_ANIMATOR_OPTIMIZE
                    Animator animatorOp = logicTarget.GetComponent<Animator>();
                    if (animatorOp.hasTransformHierarchy)
                    {
                        AnimatorUtility.OptimizeTransformHierarchy(logicTarget, m_extraExposedTransformPaths.ToArray());
                    }
#endif
                    //SetHookPoint(logicTarget);
                    //AddPrefabComponent(logicTarget);

                    string targetPath = Path.Combine(m_prefabDirectory, prefabName + "_outcity.prefab").Replace("\\", "/");
                    UnityEngine.Object tempPrefab;
                    if (File.Exists(targetPath))
                    {
//                        P4Utils.P4CheckOut(m_parentFolder + targetPath);
                        tempPrefab = AssetDatabase.LoadAssetAtPath(targetPath, typeof(GameObject));
                    }
                    else
                    {
                        tempPrefab = PrefabUtility.CreateEmptyPrefab(targetPath);
                    }
                    PrefabUtility.ReplacePrefab(logicTarget, tempPrefab, ReplacePrefabOptions.ConnectToPrefab);
                    UnityEngine.Object.DestroyImmediate(logicTarget);
                }

                string targetArtPath = Path.Combine(m_assetPrefabDirectory, prefabName + ".prefab").Replace("\\", "/");
                UnityEngine.Object tempArtPrefab;
                if (File.Exists(targetArtPath))
                {
//                    P4Utils.P4CheckOut(m_parentFolder + targetArtPath);
                    tempArtPrefab = AssetDatabase.LoadAssetAtPath(targetArtPath, typeof(GameObject));
                }
                else
                {
                    tempArtPrefab = PrefabUtility.CreateEmptyPrefab(targetArtPath);
                }

#if USE_SHADOW_OPTIMIZE
                MeshSimplify smf = !(tempArtPrefab is GameObject) ? null : (tempArtPrefab as GameObject).GetComponent<MeshSimplify>();
                if (smf == null)
                {
                    smf = cloneTarget.AddComponent<MeshSimplify>();
                    smf.m_simplifyMode = MeshSimplify.MeshSimplifyMode.Sub_Mesh;
                    smf.m_bUseCurvature = true;
                    smf.m_bProtectTexture = true;
                    smf.m_bLockBorder = false;
                }
                else
                {
                    MeshSimplify dest = cloneTarget.AddComponent<MeshSimplify>();
                    EditorUtility.CopySerialized(smf, dest);
                    dest.m_simplifyMode = MeshSimplify.MeshSimplifyMode.Sub_Mesh;
                }
                
                
                BoneBinder boneBinder = !(tempArtPrefab is GameObject) ? null : (tempArtPrefab as GameObject).GetComponent<BoneBinder>();
                if (boneBinder == null)
                {
                    cloneTarget.transform.AddComponent<BoneBinder>();
                }
                else
                {
                    BoneBinder newBinder = cloneTarget.AddComponent<BoneBinder>();
                    EditorUtility.CopySerialized(boneBinder, newBinder);
                }
#endif
                PrefabUtility.ReplacePrefab(cloneTarget, tempArtPrefab, ReplacePrefabOptions.ConnectToPrefab);

                cloneTarget.transform.position = new Vector3(offset, 0, 0);
                offset += sm.bounds.size.x;

                if ((levelName.Contains("_low"))
                    && s_bMeshBake)
                {
//                    MeshVerticesBaker baker = new MeshVerticesBaker();
//                    baker.prefabFolderPath = bakerPefabFolderPath;
//                    baker.ToGenerate(targetArtPath);
                }

                if (s_bGpuAnimation)
                {
                    string objName = prefabName + "_inst";
                    string prefabPath = Path.Combine(m_prefabDirectory, objName + ".prefab");
                    UnityEngine.Object oldPrefab;
                    if (File.Exists(prefabPath))
                    {
//                        P4Utils.P4CheckOut(m_parentFolder + prefabPath);
                        oldPrefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
                    }
                    else
                    {
                        oldPrefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
                        P4Add(m_parentFolder + prefabPath);
                    }

                    GameObject newPrefab = new GameObject(objName);

                    Material instanceMat = null;
                    Material shadowMat = null;
                    GetInstanceMaterial(prefabName, out instanceMat, out shadowMat);

                    var meshVertices = newPrefab.AddComponent<ModelInstaning>();
                    meshVertices.mat = instanceMat;
                    meshVertices.shadowMat = shadowMat;
                    meshVertices.shadowMesh = targetMesh;
                    meshVertices.animationInfo = gpuAnim;
                    
                    PrefabUtility.ReplacePrefab(newPrefab, oldPrefab);
                    UnityEngine.Object.DestroyImmediate(newPrefab);
                }
            }
        }

        private static void ExportPrefabByList(GameObject obj, RuntimeAnimatorController modelAnimatorA, List<string> prefabNames)
        {
            if(prefabNames == null)
            {
                prefabNames = new List<string>() { string.Empty };
            }

            for (int s = 0; s < prefabNames.Count; s++)
            {
                string assetName = m_assetName;
                string levelName = assetName.Replace(m_assetName, string.Empty);
              
                if (levelName.Contains("_high")) continue;

                string prefabName = assetName;
                if(!string.IsNullOrEmpty(prefabNames[s]))
                    prefabName = prefabName + "_" + prefabNames[s];

                GameObject cloneTarget = UnityEngine.Object.Instantiate<GameObject>(obj);
                cloneTarget.name = assetName;

                MatInformation matInformation = new MatInformation();
                matInformation.matName = prefabName;
                matInformation.shaderName = "Mobile/Common/UnlitWallShader";

                SkinnedMeshRenderer renderer = cloneTarget.GetComponentInChildren<SkinnedMeshRenderer>();
                if (renderer != null)
                {
                    renderer.sharedMaterials = new Material[] { AddMaterial(matInformation) };
                }

                if (modelAnimatorA != null)
                {
                    Animator animator = cloneTarget.GetComponent<Animator>();
                    if (animator != null)
                    {
                        animator.avatar = m_roleSourceAvatar;
                        animator.runtimeAnimatorController = modelAnimatorA;
                    }

                    GameObject logicTarget = UnityEngine.Object.Instantiate<GameObject>(cloneTarget);

#if USE_ANIMATOR_OPTIMIZE
                    Animator animatorOp = logicTarget.GetComponent<Animator>();
                    if (animatorOp.hasTransformHierarchy)
                    {
                        AnimatorUtility.OptimizeTransformHierarchy(logicTarget, m_extraExposedTransformPaths.ToArray());
                    }
#endif
                    SetHookPoint(logicTarget);
                    AddPrefabComponent(logicTarget);

                    string targetPath = Path.Combine(m_prefabDirectory, prefabName + ".prefab").Replace("\\", "/");
                    UnityEngine.Object tempPrefab = null;
                    if (File.Exists(targetPath))
                    {
//                        P4Utils.P4CheckOut(m_parentFolder + targetPath);
                        tempPrefab = AssetDatabase.LoadAssetAtPath(targetPath, typeof(GameObject));
                    }
                    else
                    {
                        tempPrefab = PrefabUtility.CreateEmptyPrefab(targetPath);
                    }
                    PrefabUtility.ReplacePrefab(logicTarget, tempPrefab, ReplacePrefabOptions.ConnectToPrefab);
                    UnityEngine.Object.DestroyImmediate(logicTarget);
                }

                string targetArtPath = Path.Combine(m_assetPrefabDirectory, prefabName + ".prefab").Replace("\\", "/");
                UnityEngine.Object tempArtPrefab;
                if (File.Exists(targetArtPath))
                {
//                    P4Utils.P4CheckOut(m_parentFolder + targetArtPath);
                    tempArtPrefab = AssetDatabase.LoadAssetAtPath(targetArtPath, typeof(GameObject));
                }
                else
                {
                    tempArtPrefab = PrefabUtility.CreateEmptyPrefab(targetArtPath);
                }

                PrefabUtility.ReplacePrefab(cloneTarget, tempArtPrefab, ReplacePrefabOptions.ConnectToPrefab);
            }
        }


        private static string m_materialDirectory;
        private static string m_textureDirectory;

        private static Material AddMaterial(MatInformation matInformation)
        {
            string materialPath = m_materialDirectory + matInformation.matName + ".mat";
            Material mat = null;
            Texture mainTexture = null;
            Texture maskTexture = null;
            if (File.Exists(materialPath))
            {
                mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
            }
            else
            {
                string textureName = matInformation.matName.Replace("mat", "tex");
                string mainTexturePath = m_textureDirectory + textureName + ".tga";
                if (!File.Exists(mainTexturePath))
                {
                    mainTexturePath = m_textureDirectory + textureName + ".png";
                }

                string maskTexturePath = m_textureDirectory + textureName + "_m.tga";
                if (!File.Exists(maskTexturePath))
                {
                    maskTexturePath = m_textureDirectory + textureName + "_m.png";
                    if (!File.Exists(maskTexturePath))
                    {
                        maskTexturePath = null;
                    }
                }

                mainTexture = AssetDatabase.LoadAssetAtPath<Texture>(mainTexturePath);               
                Debug.LogError("材质不存在 materialPath:" + materialPath);

                Shader shader = Shader.Find("RTS/RTSDiffuse");
                mat = new Material(shader);

                mat.SetTexture(GameFramework.Battle.Core.Uniforms._MainTex, mainTexture);
                if (maskTexturePath != null)
                {
                    maskTexture = AssetDatabase.LoadAssetAtPath<Texture>(maskTexturePath);
                    mat.SetTexture(GameFramework.Battle.Core.Uniforms._MaskTex, maskTexture);
                }
                CheckOut(m_parentFolder + materialPath);
                AssetDatabase.CreateAsset(mat, materialPath);
            }
            return mat;
        }

        private static void GetInstanceMaterial(string srcMatName, out Material instanceMat, out Material instanceShadowMat)
        {
            string materialPath = m_materialDirectory + "mat_"+srcMatName + "_slg_instance.mat";
            string shadowMaterialPath = m_materialDirectory + "mat_" + srcMatName + "_slg_instance_shadow.mat";
            
            Shader shader = Shader.Find("GGame/HRP/MainCity/GPUSkinning");
            if (File.Exists(materialPath))
            {
                instanceMat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
                //instanceMat.CopyPropertiesFromMaterial(srcMat);
            }
            else
            {
                instanceMat = new Material(shader);
                AssetDatabase.CreateAsset(instanceMat, materialPath);
            }
            //替换main贴图
            string textureName = "tex_" + srcMatName;
            string mainTexturePath = m_textureDirectory + textureName + ".tga";
            if (!File.Exists(mainTexturePath))
            {
                mainTexturePath = m_textureDirectory + textureName + ".png";
            }

            string maskTexturePath = m_textureDirectory + textureName + "_m.tga";
            if (!File.Exists(maskTexturePath))
            {
                maskTexturePath = m_textureDirectory + textureName + "_m.png";
                if (!File.Exists(maskTexturePath))
                {
                    maskTexturePath = null;
                }
            }
            var mainTexture = AssetDatabase.LoadAssetAtPath<Texture>(mainTexturePath);
            instanceMat.SetTexture("_MainTex", mainTexture);

            instanceMat.shader = shader;
            instanceMat.enableInstancing = true;

            Shader shadowShader = Shader.Find("GGame/HRP/MainCity/GPUSkinningShadow");
            if (File.Exists(shadowMaterialPath))
            {
                instanceShadowMat = AssetDatabase.LoadAssetAtPath<Material>(shadowMaterialPath);
            }
            else
            {
                instanceShadowMat = new Material(shadowShader);
                AssetDatabase.CreateAsset(instanceShadowMat, shadowMaterialPath);
            }

            instanceShadowMat.shader = shadowShader;
            instanceShadowMat.enableInstancing = true;

        }
        
        private static GameObject SetShadow(GameObject target)
        {
            string assetName = target.name;
            GameObject shadowObj = null;
            if (assetName.EndsWith("low"))
            {
                shadowObj = UnityEngine.Object.Instantiate<GameObject>(AssetDatabase.LoadAssetAtPath<GameObject>(SoldierShadowPrefabPath));
                shadowObj.name = "shadow";
                shadowObj.transform.SetParent(target.transform);
                shadowObj.transform.localPosition = Vector3.zero;
                shadowObj.transform.localEulerAngles = Vector3.zero;
                shadowObj.transform.localScale = Vector3.one;
                Transform childTransform = shadowObj.transform.Find("shadow");
                //配置阴影大小
                string toLowerName = assetName.ToLower();
                if (toLowerName.Contains("rider") || toLowerName.Contains("commander"))
                {
                    childTransform.localScale = new Vector3(4, 4, 4);
                }
                else
                {
                    childTransform.localScale = new Vector3(2, 2, 2);
                }
            }

            return shadowObj;
        }

       

        private static void SetHookPoint(GameObject target)
        {
            if (m_exportInformation.hookPoint != null)
            {
                string[] hookPoints = m_exportInformation.hookPoint.Split(';');
                for (int i = 0; i < hookPoints.Length; i++)
                {
                    string[] hookPointStrs = hookPoints[i].Split(':');
                    string parentName = hookPointStrs[0];
                    string childName = hookPointStrs[1];
                    float x = float.Parse(hookPointStrs[2]);
                    float y = float.Parse(hookPointStrs[3]);
                    float z = float.Parse(hookPointStrs[4]);
                    string childPath = Path.Combine(m_assetDirectory, childName) + ".prefab";
                    GameObject child = UnityEngine.Object.Instantiate<GameObject>(AssetDatabase.LoadAssetAtPath<GameObject>(childPath));
                    child.name = childName;
                    Transform parent = FindObj(target, parentName);
                    Transform childTransform = null;
                    if (parentName.Contains(" "))
                    {
                        string pName = parentName.Replace(" ", "");
                        childTransform = parent.Find(pName);
                        if (childTransform == null)
                        {
                            GameObject obj = new GameObject(pName);
                            childTransform = obj.transform;
                            childTransform.SetParent(parent);
                            childTransform.localPosition = Vector3.zero;
                            childTransform.localEulerAngles = Vector3.zero;
                            childTransform.localScale = Vector3.one;
                        }
                    }
                    else
                    {
                        childTransform = parent;
                    }
                    child.transform.SetParent(childTransform);
                    child.transform.localPosition = Vector3.zero;
                    child.transform.localEulerAngles = new Vector3(x, y, z);
                    child.transform.localScale = Vector3.one;
                }
            }
        }

        private static void AddPrefabComponent(GameObject target)
        {
            List<Transform> logicTransforms = new List<Transform>();
            for (int i = 0; i < m_exportInformation.logicBones.Count; i++)
            {
                string logicBoneName = m_exportInformation.logicBones[i];
                Transform parent = FindObj(target, logicBoneName);
                Transform child = null;
                if (parent == null)
                {
                    Debug.LogError(logicBoneName + "---->logicBone is not exist");
                }
                else
                {
                    if (logicBoneName.Contains(" "))
                    {
                        string logicName = logicBoneName.Replace(" ", "");
                        child = parent.Find(logicName);
                        if (child == null)
                        {
                            GameObject obj = new GameObject(logicName);
                            child = obj.transform;
                            child.SetParent(parent);
                            child.localPosition = Vector3.zero;
                            child.localEulerAngles = Vector3.zero;
                            child.localScale = Vector3.one;
                        }
                    }
                    else
                    {
                        child = parent;
                    }
                }

                if(child != null)
                    logicTransforms.Add(child);
            }
            SkinnedMeshRenderer smr = target.GetComponentInChildren<SkinnedMeshRenderer>();
            Animator animator = target.GetComponentInChildren<Animator>();
            if (m_optimizeType == OptimizeType.Commander)
            {
//                ModelCommander data = target.AddComponent<ModelCommander>();
//                data.components = new List<Component>() { animator };
//                //加上配置的骨骼
//                data.transforms = logicTransforms;
            }
//            else if (m_optimizeType == OptimizeType.Wall)
//            {
//                GameFramework.Battle.Core.ModelCity data = target.AddComponent<GameFramework.Battle.Core.ModelCity>();
//                data.components = new List<Component>() { animator };
//                //加上配置的骨骼
//                data.transforms = logicTransforms;
//            }
        }

        public class AnimationClipOverrides : List<KeyValuePair<AnimationClip, AnimationClip>>
        {
            public AnimationClipOverrides(int capacity) : base(capacity) { }

            public bool HasAnimationClip(string name)
            { return this.Find(x => x.Key.name.Equals(name)).Value != null ? true : false; }

            public AnimationClip this[string name]
            {
                get
                {
                    return this.Find(x => x.Key.name.Equals(name)).Value;
                }
                set
                {
                    int index = this.FindIndex(x => x.Key.name.Equals(name));
                    if (index != -1)
                        this[index] = new KeyValuePair<AnimationClip, AnimationClip>(this[index].Key, value);
                    else
                        Debug.LogError("没有匹配 animatoin clip：" + name);
                }
            }
        }
        
        //设置Avator自定义骨骼数据
        private static void InitalizeRigAndAnimationImporter(bool animationImporter, Avatar avatorImpoter)
        {
            m_importer.optimizeGameObjects = false;
            m_importer.extraExposedTransformPaths = null;
            m_importer.sourceAvatar = avatorImpoter;

            if (animationImporter)
            {
                m_importer.importAnimation = true;
                m_importer.resampleCurves = true;
                m_importer.animationType = ModelImporterAnimationType.Generic;
                m_importer.animationCompression = ModelImporterAnimationCompression.Optimal;
                m_importer.animationPositionError = 0.1f;
                m_importer.animationRotationError = 0.1f;
                m_importer.animationScaleError = 0.1f;

            }
            else
            {
                m_importer.importAnimation = false;
            }

            m_importer.SaveAndReimport();
            //AssetDatabase.Refresh();
        }

        private static OptimizeType GetOptimizeType(string assetName)
        {
            string toLowerName = assetName.ToLower();
            if (toLowerName.Contains("commander") || toLowerName.Contains("monster"))
            {
               return OptimizeType.Commander;
            }
            
            if (toLowerName.Contains("moto"))
            {
                return OptimizeType.Moto;
            }

            if (toLowerName.Contains("soldier") 
                || toLowerName.Contains("npcguard")
                || toLowerName.Contains("wildguard") )
            {
                return OptimizeType.Soldier;
            }

            if (toLowerName.Contains("battle"))
            {
                return OptimizeType.Wall;
            }

            if (toLowerName.Contains("citynpc") || toLowerName.Contains("_rts"))
            {
                return OptimizeType.CityNpc;
            }

            if (toLowerName.Contains("ai_hero") || toLowerName.Contains("ai_soldier"))
            {
                return OptimizeType.CityHero;
            }

            return OptimizeType.None;
        }
        
        private static bool GetAvatar(string assetPath)
        {
            UnityEngine.Object[] objs = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            m_clipList.Clear();
            for (int i = 0; i < objs.Length; i++)
            {
                if (objs[i] is Avatar)
                {
                    m_roleSourceAvatar = objs[i] as Avatar;
                }
            }

            if (m_roleSourceAvatar == null)
            {
                Debug.LogError("没有找到 Avatar." + assetPath);
                return false;
            }

            if (m_optimizeType != OptimizeType.Wall)
            {
                string avatarPath = Path.Combine(Path.GetDirectoryName(m_assetPath), m_assetName) + "_avatar.asset";
                m_roleSourceAvatar = UnityEngine.Object.Instantiate<Avatar>(m_roleSourceAvatar);
                CheckOut(m_parentFolder + avatarPath);
                //AssetDatabase.DeleteAsset(avatarPath);
                AssetDatabase.CreateAsset(m_roleSourceAvatar, avatarPath);
            }

            return true;
        }

        //获取所有动画，将AnimationClip放入m_clipList
        private static void GetAnimClips(string assetPath)
        {
            var pathArray = assetPath.Split('/');
            assetPath = Path.Combine(Path.GetDirectoryName(m_assetDirectory), "Animations/").Replace("\\", "/");
            List<UnityEngine.Object> animationList= new List<Object>();
            if (Directory.Exists(assetPath)){  

                DirectoryInfo direction = new DirectoryInfo(assetPath);  

                FileInfo[] files = direction.GetFiles("*",SearchOption.AllDirectories);  

                Debug.Log(files.Length);  

                for(int i=0;i<files.Length;i++){  

                    if (files[i].Name.EndsWith(".meta")){  

                        continue;  

                    }

                    var animation = AssetDatabase.LoadMainAssetAtPath(assetPath + files[i].Name );
                    animationList.Add(animation);
                    Debug.Log( "Name:" + files[i].Name );  
                }  

            }
            UnityEngine.Object[] objs = animationList.ToArray();
            m_clipList.Clear();
            for (int i = 0; i < objs.Length; i++)
            {
                if (objs[i] is AnimationClip)
                {
                    if (objs[i].hideFlags == (HideFlags.HideInHierarchy | HideFlags.NotEditable))
                        continue;

                    if (!IslegalString(objs[i].name))
                    {
                        string strLog = string.Format("AnimationCLip  命名错误: {0} -> {1}", assetPath, objs[i].name);
                        Warning("命名错误", strLog);
                    }

                    m_clipList.Add(objs[i] as AnimationClip);
                }
            }
        }

        private static void P4Add(string path)
        {
//            P4Utils.P4Add(path);
//            P4Utils.P4Add(path + ".meta");
        }

        private static void CheckOut(string path)
        {
//            P4Utils.P4CheckOut(path);
//            P4Utils.P4CheckOut(path + ".meta");
        }


        /// <summary>
        /// 过度条件
        /// </summary>
        private class TransitionCondition
        {
            //原AnimatorState的名字
            public string source;
            //目的AnimatorState的名字
            public string target;
            //以下是Unity  AnimatorStateTransition的属性
            public float exitTime;
            public float duration;
            public float offset;
            public bool hasExitTime;
            public bool hasFixedDuration;
            public bool canTransitionToSelf;
            public int interruptionSource;
            public bool orderedInterruption;
        }

        private class MatInformation
        {
            public string matName;
            public string shaderName;
            public List<string> modelNames;
        }

        
        private class ExportInformation
        {
            public string modelName;
            public List<string> logicBones;
            public string hookPoint;
            public List<string> prefabs;
            public Vector3 extralScale = Vector3.one;
            public Vector3 extralAngle = Vector3.zero;
        }

        private static List<ExportInformation> m_exportInformations = new List<ExportInformation>();

        static void GetExportGameObject()
        {
            m_exportInformations.Clear();

            string sp0 = "##"; //缩放和角度
            string sp1 = "@@";//prefab
            string sp2 = "$$";//bone
            //模型名字$$骨骼$$骨骼@@prefab名字$$prefab名字$$prefab名字##
            string[] lines = File.ReadAllLines(Application.dataPath + "/Arts/Character/CommanderSetConfig.txt");
            for (int i = 0; i < lines.Length; i++)
            {
                string[] ls0 = lines[i].Split(new string[] { sp0 }, StringSplitOptions.None);
                string[] ls1 = ls0[0].Split(new string[] { sp1 }, StringSplitOptions.None);
                string[] ls2 = ls1[0].Split(new string[] { sp2 }, StringSplitOptions.None);
                string fbx = ls2[0];
                ExportInformation op = new ExportInformation() { modelName = fbx, logicBones = new List<string>(), prefabs = new List<string>() };

                //收集骨骼
                for (int n = 1; n < ls2.Length; n++)
                {
                    if (ls2[n] != string.Empty && !op.logicBones.Contains(ls2[n].Replace("\\", "/")))
                        op.logicBones.Add(ls2[n].Replace("\\", "/"));
                }
                //收集prefab
                if (ls1.Length > 1)
                {
                    string[] ls = ls1[1].Split(new string[] { sp2 }, StringSplitOptions.None);
                    for (int p = 0; ls != null && p < ls.Length; p++)
                    {
                        if (ls[p] != string.Empty)
                            op.prefabs.Add(ls[p].Replace("\\", "/"));
                    }
                }
                //额外的缩放和角度信息
                if (ls0.Length > 1)
                {
                    string[] extrals = ls0[1].Split(';');
                    string[] scaleExtrals = extrals[0].Split(',');
                    op.extralScale = new Vector3(float.Parse(scaleExtrals[0]), float.Parse(scaleExtrals[1]), float.Parse(scaleExtrals[2]));
                    string[] angleExtrals = extrals[1].Split(',');
                    op.extralAngle = new Vector3(float.Parse(angleExtrals[0]), float.Parse(angleExtrals[1]), float.Parse(angleExtrals[2]));
                }

                m_exportInformations.Add(op);

            }
        }

        private static ExportInformation GetExportInformation(string name, OptimizeType mOptimizeType)
        {
            for (int i = 0; m_exportInformations != null && i < m_exportInformations.Count; i++)
            {
                if (m_exportInformations[i].modelName == name)
                {
                    return m_exportInformations[i];
                }
            }
            //对于默认的FBX，只导出Bip001
            ExportInformation exportInformation = new ExportInformation();
            exportInformation.modelName = m_assetName;
            exportInformation.logicBones = new List<string>() { "Bip001" ,"Point_motuo"};
            return exportInformation;
        }
    }
}
